import AgoraRTM from 'agora-rtm-sdk'
import { roomStore } from './room'
const ENABLE_LOG = false // 是否上传日志
const logFilter = ENABLE_LOG ? AgoraRTM.LOG_FILTER_DEBUG : AgoraRTM.LOG_FILTER_OFF

export class RoomMessage {
  muteAudio = 101
  unmuteAudio = 102
  muteVideo = 103
  unmuteVideo = 104
  applyCoVideo = 105
  acceptCoVideo = 106
  rejectCoVideo = 107
  cancelCoVideo = 108
  muteChat = 109
  unmuteChat = 110
  muteBoard = 200
  unmuteBoard = 201
  lockBoard = 301
  unlockBoard = 302
  startCourse = 401
  endCourse = 402
  muteAllChat = 501
  unmuteAllChat = 502
}

export const ChatCmdType = {
  chat: 1,
  roomMemberChanged: 2,
  roomInfoChanged: 3,
  coVideoUsersChanged: 4,
  replay: 5,
  screenShare: 6,
  recordStateChanged: 7
}

export const CoVideoType = {
  studentSendApply: 1,
  teacherSendReject: 2,
  teacherSendAccept: 4,
  teacherSendStop: 5,
  studentSendStop: 6
}

export default class AgoraRTMClient {
  constructor() {
    this._channels = {}
    this._currentChannel = null
    this._currentChannelName = null
    this._channelAttrsKey = null
    this._client = null
    this._logged = false
    this._joined = false
  }

  // 创建房间
  async login(appID, uid, token) {
    // 创建并返回一个 RtmClient 实例
    const rtmClient = AgoraRTM.createInstance(appID, { enableLogUpload: ENABLE_LOG, logFilter })
    try {
      // 登录 Agora RTM 系统
      await rtmClient.login({ uid, token })
      rtmClient.on('ConnectionStateChanged', (newState, reason) => {
        console.log(newState, reason)
      })
      rtmClient.on('MessageFromPeer', (message, peerId, props) => {
        let body = JSON.parse(message.text)
        roomStore
          .handlePeerMessage(body, peerId)
          .then(() => {})
          .catch(console.warn)
      })
      this._client = rtmClient
      this._logged = true
    } catch (err) {
      rtmClient.removeAllListeners()
      throw err
    }
    return
  }

  // 退出
  async logout() {
    if (!this._logged) return
    await this._client.logout()
    this._logged = false
    return
  }

  // 加入房间
  async join(channel) {
    const _channel = this._client.createChannel(channel)
    this._channels[channel] = _channel
    this._currentChannel = this._channels[channel]
    this._currentChannelName = channel
    await _channel.join()
    _channel.on('ChannelMessage', message => {
      const { cmd, data } = JSON.parse(message.text)
      console.log('ChannelMessage cmd:  ', message, cmd, JSON.stringify(data))
      // TODO: chat message
      // TODO: 更新即时聊天
      if (cmd === ChatCmdType.chat) {
        if (data.userId === roomStore.state.me.userId) return
        const chatMessage = {
          account: data.userName,
          text: data.message,
          ts: +Date.now(),
          id: data.userId,
          userAvatar: data.userAvatar
        }
        roomStore.updateChannelMessage(chatMessage)
      }
      // TODO: update room member changed
      // TODO: 更新人员进出
      if (cmd === ChatCmdType.roomMemberChanged) {
        const memberCount = data.total
        roomStore.updateRoomMember(memberCount)
      }

      // TODO: update course state
      // TODO: 更新房间信息
      if (cmd === ChatCmdType.roomInfoChanged) {
        roomStore.updateRoomInfo({
          muteAllChat: data.muteAllChat,
          lockBoard: data.lockBoard,
          courseState: data.courseState,
          startTime: data.startTime
        })
      }

      // TODO: update room co-video-users
      // TODO: 更新连麦用户
      if (cmd === ChatCmdType.coVideoUsersChanged) {
        const users = data
        roomStore.updateCoVideoUsers(users)
      }

      // TODO: replay message
      // TODO: 更新录制回放
      if (cmd === ChatCmdType.replay) {
        const replayMessage = {
          account: data.userName,
          text: 'recording',
          link: data.recordId,
          ts: +Date.now(),
          id: data.uid
        }
        roomStore.updateChannelMessage(replayMessage)
      }

      // TODO: update course Share
      // TODO: 分享状态发生改变了
      if (cmd === ChatCmdType.screenShare) {
        roomStore.updateScreenShare({
          state: data.state,
          screenId: data.screenId,
          userId: data.userId
        })
      }

      // TODO: recordingStateChanged
      // TODO: 录制状态发生改变了
      if (cmd === ChatCmdType.recordStateChanged) {
        roomStore.updateRecordState({
          roomId: data.roomId,
          recordId: data.recordId,
          isRecording: data.isRecording,
          recordingTime: data.recordingTime
        })
      }
    })

    _channel.on('MemberJoined', memberId => {
      console.log(memberId, '加入了房间')
    })

    _channel.on('MemberLeft', memberId => {
      console.log(memberId, '离开了房间')
    })

    _channel.on('MemberCountUpdated', count => {
      console.log(count)
    })

    _channel.on('AttributesUpdated', attributes => {
      console.log(attributes)
    })

    this._joined = true
    return
  }

  destroyChannel(channel) {
    if (this._channels[channel]) {
      this._channels[channel].removeAllListeners()
      this._channels[channel] = null
    }
  }

  async leave(channel) {
    if (this._channels[channel]) {
      this._joined = false
      this.destroyChannel(channel)
    }
  }

  // 离开房间
  async exit() {
    try {
      await this.deleteChannelAttributesByKey()
    } catch (err) {
      let error = err
      throw error
    } finally {
      await this.leave(this._currentChannelName)
      await this.logout()
    }
  }

  // 发送消息
  async notifyMessage(params) {
    const { cmd, data, enableHistoricalMessaging = false } = params
    const body = JSON.stringify({
      cmd,
      data
    })
    return this._currentChannel.sendMessage({ text: body }, { enableHistoricalMessaging })
  }

  // 将该消息保存为历史消息
  async sendPeerMessage(peerId, body) {
    let result = await this._client.sendMessageToPeer({ text: JSON.stringify(body) }, peerId, {
      enableHistoricalMessaging: true
    })
    return result.hasPeerReceived
  }

  // 不将该消息保存为历史消息
  async sendRecordMessage(data) {
    const msgData = {
      account: data.account,
      recordId: data.recordId
    }
    return this.notifyMessage({
      cmd: ChatCmdType.replay,
      data: msgData,
      enableHistoricalMessaging: false
    })
  }

  // 历史消息
  async sendChannelMessage(data) {
    const msgData = {
      account: data.account,
      content: data.content
    }
    return this.notifyMessage({
      cmd: ChatCmdType.chat,
      data: msgData,
      enableHistoricalMessaging: true
    })
  }

  // 更新
  async updateChannelAttrsByKey(key, attrs) {
    this._channelAttrsKey = key
    const channelAttributes = {}
    if (key) {
      channelAttributes[key] = JSON.stringify(attrs)
    }
    await this._client.addOrUpdateChannelAttributes(this._currentChannelName, channelAttributes, {
      enableNotificationToChannelMembers: true
    })
  }

  // 删除
  async deleteChannelAttributesByKey() {
    if (!this._channelAttrsKey) return
    await this._client.deleteChannelAttributesByKeys(
      this._currentChannelName,
      [this._channelAttrsKey],
      {
        enableNotificationToChannelMembers: true
      }
    )
    this._channelAttrsKey = null
    return
  }

  async getChannelAttrs() {
    let json = await this._client.getChannelAttributes(this._currentChannelName)
    return JSON.stringify(json)
  }

  async getChannelMemberCount(ids) {
    return this._client.getChannelMemberCount(ids)
  }

  async queryOnlineStatusBy(accounts) {
    let results = {
      teacherCount: 0,
      totalCount: 0,
      studentTotalCount: 0
    }
    if (accounts.length > 0) {
      const ids = accounts.map(it => `${it.uid}`)
      results = await this._client.queryPeersOnlineStatus(ids)
      if (results && Object.keys(results).length) {
        const teacher = accounts.find(it => it.role === 'teacher')
        if (teacher && results[teacher.uid]) {
          results.teacher = results[teacher.uid]
          results.teacherCount = 1
        }
        results.totalCount = accounts.filter(it => results[it.uid]).length
        results.studentsTotalCount = results.totalCount - results.teacherCount
      } else {
        console.warn(
          `accounts: ${ids}, cannot get peers online status from [queryPeersOnlineStatus]`
        )
      }
    }
    return results
  }

  async getChannelAttributeBy(channelName) {
    let json = await this._client.getChannelAttributes(channelName)
    const accounts = []
    for (let key of Object.keys(json)) {
      if (key === 'teacher') {
        const teacherObj = JSON.parse(json, `${key}.value`)
        // when teacher is not empty object
        if (teacherObj && Object.keys(teacherObj).length) {
          accounts.push({ role: 'teacher', ...teacherObj })
        }
        continue
      }
      const student = JSON.parse(json, `${key}.value`)
      // when student is not empty object
      if (student && Object.keys(student).length) {
        student.uid = key
        accounts.push(student)
      }
    }
    return accounts
  }
}
